
`include "defines.v"
`define AXI_TOP_INTERFACE(name) io_memAXI_0_``name

module SimTop(
    input                               clock,
    input                               reset,

    input  [63:0]                       io_logCtrl_log_begin,
    input  [63:0]                       io_logCtrl_log_end,
    input  [63:0]                       io_logCtrl_log_level,
    input                               io_perfInfo_clean,
    input                               io_perfInfo_dump,

    output                              io_uart_out_valid,
    output [7:0]                        io_uart_out_ch,
    output                              io_uart_in_valid,
    input  [7:0]                        io_uart_in_ch,

    input                               `AXI_TOP_INTERFACE(aw_ready),
    output                              `AXI_TOP_INTERFACE(aw_valid),
    output [`AXI_ADDR_WIDTH-1:0]        `AXI_TOP_INTERFACE(aw_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_prot),
    output [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(aw_bits_id),
    output [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(aw_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(aw_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(aw_bits_burst),
    output                              `AXI_TOP_INTERFACE(aw_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_qos),
    
    input                               `AXI_TOP_INTERFACE(w_ready),
    output                              `AXI_TOP_INTERFACE(w_valid),
    output [`AXI_DATA_WIDTH-1:0]        `AXI_TOP_INTERFACE(w_bits_data)         [3:0],
    output [`AXI_DATA_WIDTH/8-1:0]      `AXI_TOP_INTERFACE(w_bits_strb),
    output                              `AXI_TOP_INTERFACE(w_bits_last),
    
    output                              `AXI_TOP_INTERFACE(b_ready),
    input                               `AXI_TOP_INTERFACE(b_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(b_bits_resp),
    input  [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(b_bits_id),
    input  [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(b_bits_user),

    input                               `AXI_TOP_INTERFACE(ar_ready),
    output                              `AXI_TOP_INTERFACE(ar_valid),
    output [`AXI_ADDR_WIDTH-1:0]        `AXI_TOP_INTERFACE(ar_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_prot),
    output [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(ar_bits_id),
    output [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(ar_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(ar_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(ar_bits_burst),
    output                              `AXI_TOP_INTERFACE(ar_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_qos),
    
    output                              `AXI_TOP_INTERFACE(r_ready),
    input                               `AXI_TOP_INTERFACE(r_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(r_bits_resp),
    input  [`AXI_DATA_WIDTH-1:0]        `AXI_TOP_INTERFACE(r_bits_data)         [3:0],
    input                               `AXI_TOP_INTERFACE(r_bits_last),
    input  [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(r_bits_id),
    input  [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(r_bits_user)
);

    wire aw_ready;
    wire aw_valid;
    wire [`AXI_ADDR_WIDTH-1:0] aw_addr;
    wire [2:0] aw_prot;
    wire [`AXI_ID_WIDTH-1:0] aw_id;
    wire [`AXI_USER_WIDTH-1:0] aw_user;
    wire [7:0] aw_len;
    wire [2:0] aw_size;
    wire [1:0] aw_burst;
    wire aw_lock;
    wire [3:0] aw_cache;
    wire [3:0] aw_qos;
    wire [3:0] aw_region;

    wire w_ready;
    wire w_valid;
    wire [`AXI_DATA_WIDTH-1:0] w_data;
    wire [`AXI_DATA_WIDTH/8-1:0] w_strb;
    wire w_last;
    wire [`AXI_USER_WIDTH-1:0] w_user;
    
    wire b_ready;
    wire b_valid;
    wire [1:0] b_resp;
    wire [`AXI_ID_WIDTH-1:0] b_id;
    wire [`AXI_USER_WIDTH-1:0] b_user;

    wire ar_ready;
    wire ar_valid;
    wire [`AXI_ADDR_WIDTH-1:0] ar_addr;
    wire [2:0] ar_prot;
    wire [`AXI_ID_WIDTH-1:0] ar_id;
    wire [`AXI_USER_WIDTH-1:0] ar_user;
    wire [7:0] ar_len;
    wire [2:0] ar_size;
    wire [1:0] ar_burst;
    wire ar_lock;
    wire [3:0] ar_cache;
    wire [3:0] ar_qos;
    wire [3:0] ar_region;
    
    wire r_ready;
    wire r_valid;
    wire [1:0] r_resp;
    wire [`AXI_DATA_WIDTH-1:0] r_data;
    wire r_last;
    wire [`AXI_ID_WIDTH-1:0] r_id;
    wire [`AXI_USER_WIDTH-1:0] r_user;

    assign ar_ready                                 = `AXI_TOP_INTERFACE(ar_ready);
    assign `AXI_TOP_INTERFACE(ar_valid)             = ar_valid;
    assign `AXI_TOP_INTERFACE(ar_bits_addr)         = ar_addr;
    assign `AXI_TOP_INTERFACE(ar_bits_prot)         = ar_prot;
    assign `AXI_TOP_INTERFACE(ar_bits_id)           = ar_id;
    assign `AXI_TOP_INTERFACE(ar_bits_user)         = ar_user;
    assign `AXI_TOP_INTERFACE(ar_bits_len)          = ar_len;
    assign `AXI_TOP_INTERFACE(ar_bits_size)         = ar_size;
    assign `AXI_TOP_INTERFACE(ar_bits_burst)        = ar_burst;
    assign `AXI_TOP_INTERFACE(ar_bits_lock)         = ar_lock;
    assign `AXI_TOP_INTERFACE(ar_bits_cache)        = ar_cache;
    assign `AXI_TOP_INTERFACE(ar_bits_qos)          = ar_qos;
    
    assign `AXI_TOP_INTERFACE(r_ready)              = r_ready;
    assign r_valid                                  = `AXI_TOP_INTERFACE(r_valid);
    assign r_resp                                   = `AXI_TOP_INTERFACE(r_bits_resp);
    assign r_data                                   = `AXI_TOP_INTERFACE(r_bits_data)[0];
    assign r_last                                   = `AXI_TOP_INTERFACE(r_bits_last);
    assign r_id                                     = `AXI_TOP_INTERFACE(r_bits_id);
    assign r_user                                   = `AXI_TOP_INTERFACE(r_bits_user);

    assign aw_ready                                 = `AXI_TOP_INTERFACE(aw_ready);
    assign `AXI_TOP_INTERFACE(aw_valid)             = aw_valid;
    assign `AXI_TOP_INTERFACE(aw_bits_addr)         = aw_addr;
    assign `AXI_TOP_INTERFACE(aw_bits_prot)         = aw_prot;
    assign `AXI_TOP_INTERFACE(aw_bits_id)           = aw_id;
    assign `AXI_TOP_INTERFACE(aw_bits_user)         = aw_user;
    assign `AXI_TOP_INTERFACE(aw_bits_len)          = aw_len;
    assign `AXI_TOP_INTERFACE(aw_bits_size)         = aw_size;
    assign `AXI_TOP_INTERFACE(aw_bits_burst)        = aw_burst;
    assign `AXI_TOP_INTERFACE(aw_bits_lock)         = aw_lock;
    assign `AXI_TOP_INTERFACE(aw_bits_cache)        = aw_cache;
    assign `AXI_TOP_INTERFACE(aw_bits_qos)          = aw_qos;
    
    assign `AXI_TOP_INTERFACE(w_valid)              = w_valid;
    assign w_ready                                  = `AXI_TOP_INTERFACE(w_ready);
    assign `AXI_TOP_INTERFACE(w_bits_data)[0]       = w_data;
    assign `AXI_TOP_INTERFACE(w_bits_strb)          = w_strb;
    assign `AXI_TOP_INTERFACE(w_bits_last)          = w_last;

    assign b_valid                                  = `AXI_TOP_INTERFACE(b_valid);
    assign `AXI_TOP_INTERFACE(b_ready)              = b_ready;
    assign b_resp                                   = `AXI_TOP_INTERFACE(b_bits_resp);
    assign b_id                                     = `AXI_TOP_INTERFACE(b_bits_id);
    assign b_user                                   = `AXI_TOP_INTERFACE(b_bits_user);;
// if_stage
wire                   [  63:0]         pc                         ;
wire                   [  31:0]         inst                       ;
reg                    [  31:0]         instr_if                   ;
reg                    [  31:0]         instr_id                   ;
reg                    [  31:0]         instr_ex                   ;
reg                    [  31:0]         instr_mem                  ;
wire                                    IM_valid                   ;
wire                                    IM_ready                   ;
wire                   [  63:0]         IM_addr                    ;
wire                   [  31:0]         IM_rdata                   ;
wire                   [  63:0]         ram_addr                   ;
wire                   [  63:0]         DM_wdata                   ;
wire                   [   7:0]         DM_wstrb                   ;
wire                   [  63:0]         DM_rdata                   ;
wire                   [  63:0]         dm_data                    ;
wire                                    DM_valid                   ;
reg                                     DM_ready                   ;
wire                   [  63:0]         DM_addr                    ;
wire                   [  63:0]         mem_addr                   ;
wire                   [  63:0]         data_addr                  ;
wire                   [  63:0]         instr_addr                 ;
reg                    [  63:0]         pc_r                       ;
reg                    [  31:0]         inst_r                     ;
reg                                     inst_vld_r                 ;
reg                                     cmt_wen_r                  ;
reg                    [   7:0]         cmt_wdest_r                ;
reg                    [  63:0]         cmt_wdata_r                ;
reg                                     skip_r                     ;
    CORE_PIPE top_inst
    (
    .clk                               (clock                       ),
    .rst_n                             (!reset                     ),
    .IM_rdy                            (IM_ready                  ),
    .IM_vld                            (IM_valid                  ),
    .DM_rdy                            (DM_ready                  ),
    .IM_rdata                          (IM_rdata                  ),
    .IM_addr                           (IM_addr                   ),
    .DM_wdata                          (DM_wdata                  ),
    .DM_wstrb                          (DM_wstrb                  ),
    .DM_vld                            (DM_valid                  ),
    .DM_addr                           (DM_addr                   ),
    .DM_rdata                          (DM_rdata                   ) 
 //   	  .trap	        (	trap		        )
    );
assign pc = IM_addr;
assign mem_addr = DM_addr[30:0];

always @(posedge clock) begin
    skip_r <= top_inst.instr_mem[31:20] == 12'hb00 &&  top_inst.instr_mem[6:2] == 5'b11100;
    pc_r <= top_inst.pc_mem;
    inst_r <= top_inst.instr_mem;
    inst_vld_r <= top_inst.I_vld_mem;
    cmt_wen_r <= top_inst.Wenreg_mem;
    cmt_wdest_r <= top_inst.rd_addr_mem;
    cmt_wdata_r <= top_inst.rd_mem;
end
// Difftest
reg                                     cmt_wen                    ;
reg                    [   7:0]         cmt_wdest                  ;
reg                    [  63:0]         cmt_wdata                  ;
reg                    [  63:0]         cmt_pc                     ;
reg                    [  31:0]         cmt_inst                   ;
reg                                     cmt_valid                  ;
reg                                     trap                       ;
reg                    [   7:0]         trap_code                  ;
reg                    [  63:0]         cycleCnt                   ;
reg                    [  63:0]         instrCnt                   ;
reg                                     cmt_skip                    ;
reg [63:0] regs_diff [0 : 31];
integer                 i;
always @(negedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= cmt_wen_r;
    cmt_wdest <= cmt_wdest_r;
    cmt_wdata <= cmt_wdata_r;
    cmt_valid <= inst_vld_r;
    cmt_pc <= pc_r;
    cmt_inst <= inst_r;
    trap <= inst_r[6:0] == 7'h6b;
    trap_code <= 0;//top_inst.x[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + top_inst.I_vld_mem;
    // instrCnt <= instrCnt + inst_vld_r;
    cmt_skip <= skip_r;
    for(i =1; i<32;i=i+1)
        regs_diff[i] <= top_inst.x[i];
  end
end

    MEM_AXI axi_inst(
    .clk                               (clock                     ),
    .rst_n                             (!reset                    ),
    .IM_rdy                            (IM_ready                  ),
    .IM_vld                            (IM_valid                  ),
    .DM_rdy                            (DM_ready                  ),
    .IM_rdata                          (IM_rdata                  ),
    .IM_addr                           (IM_addr                   ),
    .DM_wdata                          (DM_wdata                  ),
    .DM_wstrb                          (DM_wstrb                  ),
    .DM_vld                            (DM_valid                  ),
    .DM_addr                           (DM_addr                   ),
    .DM_rdata                          (DM_rdata                  ),
    .axi_awvalid                       (aw_valid                  ),
    .axi_awready                       (aw_ready                  ),//aw_ready
    .axi_awaddr                        (aw_addr                   ),
    .axi_awprot                        (aw_prot                   ),
    .axi_awid                          (aw_id                     ),
    .axi_awuser                        (aw_user                   ),
    .axi_awlen                         (aw_len                    ),
    .axi_awsize                        (aw_size                   ),
    .axi_awburst                       (aw_burst                  ),
    .axi_awlock                        (aw_lock                   ),
    .axi_awcache                       (aw_cache                  ),
    .axi_awqos                         (aw_qos                    ),
    .axi_awregion                      (aw_region                 ),
    .axi_wvalid                        (w_valid                   ),
    .axi_wready                        (w_ready                   ),
    .axi_wdata                         (w_data                    ),
    .axi_wstrb                         (w_strb                    ),
    .axi_wlast                         (w_last                    ),
    .axi_wuser                         (                    ),
    .axi_bvalid                        (b_valid                   ),
    .axi_bready                        (b_ready                   ),
    .axi_bresp                         (b_resp                    ),
    .axi_bid                           (b_id                      ),
    .axi_buser                         (b_user                    ),
    .axi_arvalid                       (ar_valid                  ),
    .axi_arready                       (ar_ready                  ),
    .axi_araddr                        (ar_addr                   ),
    .axi_arprot                        (ar_prot                   ),
    .axi_arid                          (ar_id                     ),
    .axi_aruser                        (ar_user                   ),
    .axi_arlen                         (ar_len                    ),
    .axi_arsize                        (ar_size                   ),
    .axi_arburst                       (ar_burst                  ),
    .axi_arlock                        (ar_lock                   ),
    .axi_arcache                       (ar_cache                  ),
    .axi_arqos                         (ar_qos                    ),
    .axi_arregion                      (ar_region                 ),
    .axi_rvalid                        (r_valid                   ),
    .axi_rready                        (r_ready                   ),
    .axi_rdata                         (r_data                    ),
    .axi_rresp                         (r_resp                    ),
    .axi_rlast                         (r_last                    ),
    .axi_rid                           (r_id                      ),
    .axi_ruser                         (r_user                    ) 
    );

// Difftest

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .skip               (cmt_skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (0),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (`RISCV_PRIV_MODE_M),
  .mstatus            (0),
  .sstatus            (0),
  .mepc               (0),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (0),
  .stvec              (0),
  .mcause             (0),
  .scause             (0),
  .satp               (0),
  .mip                (0),
  .mie                (0),
  .mscratch           (0),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);

endmodule